#include <linux/module.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/poll.h>
#include <linux/mutex.h>
#include <linux/interrupt.h>
#include <linux/device.h>
#include <net/sock.h>
#include <linux/netlink.h>
#include <linux/semaphore.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include "netlink_u.h"
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>

#define CHAR_DEBUG printk
 
#define CHAR_DEVICE_NAME "char_driver"
#define CHAR_CLASS_NAME  "char_driver_class"
#define MY_GPIO_NUM    4 // 根据你的硬件修改

static struct class *char_driver_cls;
static struct device *char_driver_dev;
static int major;
static int is_wakeup = 0;
static atomic_t my_atomic_var = ATOMIC_INIT(0);

static DECLARE_WAIT_QUEUE_HEAD(char_driver_wait);

static int char_driver_open(struct inode *node, struct file *file)
{
    CHAR_DEBUG("tsensor_open \n");
    return 0;
}

static ssize_t char_driver_read(struct file *file, char *buf, size_t len,
                loff_t *offset)
{
    CHAR_DEBUG("tsensor_read \n");

    return 0;
}

static ssize_t char_driver_write(struct file *file, const char *buf, size_t len,
                 loff_t *offset)
{
    CHAR_DEBUG("tsensor_write \n");
    return 0;
}

static int char_driver_release(struct inode *node, struct file *file)
{
    CHAR_DEBUG("tsensor_release\n");
    return 0;
}

static void my_delayed_work_callback(struct work_struct *work)
{
    int new_value = 1;
    printk("Delayed work callback function called.\n");
    device_lock(char_driver_dev);
    is_wakeup = 1;

    device_unlock(char_driver_dev);
        

    atomic_set(&my_atomic_var, new_value);
    new_value = atomic_read(&my_atomic_var);
}
static DECLARE_DELAYED_WORK(my_work, my_delayed_work_callback);

static unsigned int  char_driver_poll(struct file *file,  poll_table* wait)
{
    unsigned int mask = 0;
    printk("Handle ID: %ld\n", (int)file);
    poll_wait(file, &char_driver_wait, wait);
    if(is_wakeup)
    {
         is_wakeup = 0;
         mask |= POLLIN | POLLRDNORM;
    }
    else
    {
        schedule_delayed_work(&my_work, msecs_to_jiffies(5000)); 
    }
    return mask;
}

static struct file_operations char_driver_fops = {
    .owner = THIS_MODULE,
    .open =char_driver_open,
    .read =char_driver_read,
    .write =char_driver_write,
    .release =char_driver_release,
    .poll = char_driver_poll,
};

void recv_data_netlink_cb(char *data, int data_len)
{
    
    CHAR_DEBUG("recv data: %s \n", data);
}

//    retval = add_uevent_var(env, "ACTION=%s", action_string);
//     retval = add_uevent_var(env, "DEVPATH=%s", devpath);
//     retval = add_uevent_var(env, "SUBSYSTEM=%s", subsystem);

static void send_uevent(struct device *dev, unsigned long code)
{
        char event_string[128];
        char *envp[] = { event_string, NULL }; 
        sprintf(event_string, "EVENT=%ld",code); 
        kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
        CHAR_DEBUG(event_string);
        kobject_uevent(&dev->kobj, KOBJ_ADD);
        CHAR_DEBUG("send uevent success.\n");
}

static int my_gpio_init(void)
{
    int err;

    // err = gpio_request(MY_GPIO_NUM, "my_gpio");
    // if (err) {
    //     printk(KERN_ERR "Failed to request GPIO %d, error %d\n", MY_GPIO_NUM, err);
    //     return err;
    // }

    // err = gpio_export(MY_GPIO_NUM, false);
    // if (err) {
    //     printk(KERN_ERR "Failed to export GPIO %d, error %d\n", MY_GPIO_NUM, err);
    //     return err;
    // }

    printk(KERN_INFO "GPIO %d is successfully exported to sysfs\n", MY_GPIO_NUM);
    return 0;
}

static int __init char_driver_init(void)
{
    CHAR_DEBUG("%s enter.\n", __func__);
    major = register_chrdev(0, CHAR_DEVICE_NAME, &char_driver_fops);;  
    if (major < 0) {
        CHAR_DEBUG("Register chrdev failed.\n");
        return major;
    }

    char_driver_cls = class_create(THIS_MODULE, CHAR_CLASS_NAME);
    if (IS_ERR(char_driver_cls)) {
            unregister_chrdev(major, CHAR_DEVICE_NAME);
            CHAR_DEBUG("Unable to create char class, errno = %ld\n", PTR_ERR(char_driver_cls));
            return PTR_ERR(char_driver_cls);
    }

    char_driver_dev = device_create(char_driver_cls, NULL, MKDEV(major, 0), NULL, CHAR_DEVICE_NAME);
    if (IS_ERR(char_driver_dev)) {
        class_destroy(char_driver_cls);
        unregister_chrdev(major, CHAR_DEVICE_NAME);
        CHAR_DEBUG("Unable to create char dev, errno = %ld\n", PTR_ERR(char_driver_dev));
        return PTR_ERR(char_driver_dev);
    }    

    netlink_create_sock(recv_data_netlink_cb);

    send_uevent(char_driver_dev, 19);

    CHAR_DEBUG("char device init success.\n");

    my_gpio_init();
    
    cancel_delayed_work_sync(&my_work);
    return 0;
}


static void __exit  char_driver_deinit(void)
{
    CHAR_DEBUG("%s enter.\n", __func__);
    device_destroy(char_driver_cls, MKDEV(major, 0));
    class_destroy(char_driver_cls);
    unregister_chrdev(major, CHAR_DEVICE_NAME);
    gpio_unexport(MY_GPIO_NUM);
    gpio_free(MY_GPIO_NUM);
}





module_init(char_driver_init);
module_exit(char_driver_deinit);

MODULE_LICENSE("GPL");  